#[allow(dead_code)]
pub mod lzizyapi {
	use futures::future::join_all;
	use reqwest::Client;
	use scraper::{Html, Selector};
	use serde::{Serialize, Deserialize};
	use serde_json::Value;
	use std::{
		array, time::{Duration, Instant}
	};

	pub struct Lzizy {
		client: reqwest::Client,
		current_route: String,
		channel_page_url: String,
		is_init: bool,
	}

	#[derive(Serialize, Deserialize, Debug)]
	pub struct LzizyVideoBase {
		id: u32,
		name: String,
		cover_url: String,
	}

	#[derive(serde::Serialize, Deserialize, Debug)]
	struct EpisodeInfo {
		title: String,
		url: String,
	}

	#[derive(Serialize, Deserialize, Debug)]
	pub struct LzizyVideo {
		name: String,
		genres: String,
		cover_url: String,
		actor: Vec<String>,
		intro: String,
		director: Vec<String>,
		region: String,
		year: String,
		update_time: String,
		language: String,
		update_state: String,
		play_infos: Vec<EpisodeInfo>,
	}

	impl LzizyVideoBase {
		fn new(id: u32, name: String, cover_url: String) -> Self {
			Self {
				id,
				name,
				cover_url,
			}
		}
	}

	impl EpisodeInfo {
		fn new() -> Self {
			Self {
				title: String::new(),
				url: String::new(),
			}
		}
	}

	impl LzizyVideo {
		fn new() -> Self {
			Self {
				name: String::new(),
				genres: String::new(),
				cover_url: String::new(),
				actor: vec![],
				intro: String::new(),
				director: vec![],
				region: String::new(),
				year: String::new(),
				update_time: String::new(),
				language: String::new(),
				update_state: String::new(),
				play_infos: vec![],
			}
		}
	}

	impl Lzizy {
		pub fn new() -> Self {
			let client = reqwest::Client::builder()
				.timeout(Duration::from_secs(5))
				.pool_idle_timeout(Duration::from_secs(30))
				.tcp_keepalive(Duration::from_secs(60))
				.http2_keep_alive_interval(Duration::from_secs(30))
				.pool_max_idle_per_host(10)
				.build()
				.unwrap_or_else(|e| {
					eprintln!("Custom client failed: {}", e);
					reqwest::Client::new()
				});

			Self {
				client,
				current_route: String::new(),
				channel_page_url: String::new(),
				is_init: false,
			}
		}

		/// 测试并返回最佳视频接口线路
		async fn get_optimal_route() -> Result<String, String> {
			// 创建线路地址
			let api_routes: [String; 8] = array::from_fn(|i| {
				let id = i + 1;
				"https://lzizy@id.com".replace("@id", &id.to_string())
			});

			// 创建HTTP客户端
			let client = Client::builder()
				.pool_max_idle_per_host(8)
				.timeout(Duration::from_secs(3))
				.build()
				.map_err(|e| format!("Client build failed: {}", e))?;
			// 遍历所有请求目标的url地址，为其创建异步请求任务
			let tasks = api_routes.into_iter().map(|url| {
				let client = client.clone();

				// 异步任务块
				async move {
					let request_task = client.head(url.to_string()); // 创建请求
					let start_time = Instant::now(); // 起始时间

					request_task
						.send()
						.await
						.map(|res| {
							let duration = start_time.elapsed().as_secs_f32(); // 结束时间
							println!("[线路耗时]: {}  {}", res.url(), duration);
							(url.to_string(), duration)
						})
						.map_err(|e| format!("请求失败: {}", e))
				}
			});

			// 发送所有请求任务
			let responses = join_all(tasks).await;

			// 计算并选出用时最短的数据（类型为元组）
			let result = responses
				.into_iter()
				// 过滤无效的请求结果
				.filter_map(|item| match item {
					Ok(data) => Some(data),
					Err(e) => {
						eprintln!("{}", e);
						None
					}
				})
				// 遍历计算耗时最短的那个请求的后果数据
				.min_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
			// 取出并返回用时最短的线路地址
			let url = result.map_or(String::new(), |v| v.0.to_string());
			Ok(url.clone())
		}
	}

	impl Lzizy {
		pub async fn init(&mut self) {
			if self.is_init {
				return;
			}
			self.current_route = Lzizy::get_optimal_route().await.ok().unwrap();
			self.channel_page_url = format!(
				"{}/index.php/vod/type/id/@cid/page/1.html",
				self.current_route
			);
			self.is_init = true;
			println!("[lzizy_api]：初始化成功！");
		}

		pub async fn get_channel_page(&self, channel_index: u8) -> Result<String, String> {
			println!("get_channel_page({})", channel_index);

			// 将频道索引映射到目标页面id
			let cid = match channel_index {
				0 => 6,
				1 => 13,
				2 => 29,
				3 => 25,
				_ => return Err(format!("无效的频道索引！({})", channel_index)),
			};
			// 合成请求地址
			let url = self.channel_page_url.replace("@cid", &cid.to_string());

			// 创建并发起请求，获取其响应对象
			let response = self
				.client
				.get(&url)
				.send()
				.await
				.map_err(|e| format!("请求错误！{}", e))?;

			// 判断目标站点是否响应成功
			if !response.status().is_success() {
				return Err(format!("[无法访问]: {}", url));
			}

			// 取得响应页面
			let html = response.text().await.map_err(|e| format!("{}", e))?;

			// 返回页面内容
			Ok(html)
		}

		/// 获取目标页面地址
		pub fn get_target_page_url(&self, channel_page: String) -> Vec<String> {
			let dom = scraper::Html::parse_fragment(&channel_page);
			let select = scraper::Selector::parse(".videoContent > li > a:nth-child(1)").unwrap();
			let video_content = dom.select(&select);
			let mut urls: Vec<String> = vec![];

			for node in video_content {
				if let Some(v) = node.value().attr("href") {
					urls.push(format!("{}{}", self.current_route, v));
				}
			}
			urls
		}

		/// 获取目标页面内容
		pub async fn get_target_page(&self, page_urls: Vec<String>) -> Vec<String> {
			// 生成并发任务流
			let tasks = page_urls.iter().map(|url| {
				// 为每个任务克隆必要数据
				// let client = self.client.clone();

				async move {
					// 根据method参数提供的请求方式构建相应的请求实例
					let request_builder = self.client.get(url);

					// 发送请求并处理响应
					match request_builder.send().await {
						Ok(res) => match res.text().await {
							Ok(text) => Ok(text),
							Err(e) => Err(format!("[数据获取失败]: {}", e)),
						},
						Err(e) => Err(format!("[请求失败]: {}", e)),
					}
				}
			});

			let results = join_all(tasks).await;
			let htmls: Vec<String> = results.into_iter().filter_map(Result::ok).collect();

			htmls
		}

		pub async fn get_video_data(&self, target_page: String) -> Result<LzizyVideo, String> {
			let doc = Html::parse_fragment(&target_page);

			// 视频封面
			let select =
				Selector::parse("font > b > div:nth-child(3) > div > div.left > img").unwrap();
			let mut elements = doc.select(&select);
			let cover_url = elements.next().unwrap().attr("src").unwrap().to_string();

			// 视频信息
			let select =
				Selector::parse("font > b > div:nth-child(3) > div > div.right > p").unwrap();
			let mut elements = doc.select(&select);

			let name: String = elements.next().unwrap().text().next().unwrap().replace("片名：", "");
			elements.next();
			elements.next();
			let update_state = elements.next().unwrap().text().next().unwrap().replace("状态：", "");
			let video_type = elements.next().unwrap().text().collect::<String>().replace("类型：", "").replace('\u{a0}', ",").trim_end_matches(",").to_string();
			let director = elements.next().unwrap().text().collect::<String>().replace("导演：", "").split(",").map(|v| v.to_string()).collect();
			let actor = elements.next().unwrap().text().collect::<String>().replace("演员：", "").split(",").map(|v| v.to_string()).collect();
			let time = elements.next().unwrap().text().next().unwrap().replace("年代：", "");
			let area = elements.next().unwrap().text().next().unwrap().replace("地区：", "");
			let language = elements.next().unwrap().text().next().unwrap().replace("语言：", "");
			elements.next();
			let update_time = elements.next().unwrap().text().next().unwrap().replace("更新时间：", "");

			// 视频介绍
			let select = Selector::parse("#content > div > p").unwrap();
			let mut elements = doc.select(&select);
			let intro = elements.next().unwrap().text().next().unwrap().trim().to_string();

			// 视频地址
			// let select = Selector::parse(".playlist.wbox.http > li > a[href$='.mp4']").unwrap();
			let select = Selector::parse(".playlist.wbox.liangzi > li > a[href^='http']").unwrap();
			let elements = doc.select(&select);
			let mut play_infos = vec![];
			for element in elements {
				let title = element.attr("title").unwrap().to_string();
				let url = element.attr("href").unwrap().to_string();
				play_infos.push(EpisodeInfo { title, url });
			}

			Ok(LzizyVideo {
				cover_url,
				name,
				update_state,
				genres: video_type,
				director,
				actor,
				year: time,
				region: area,
				language,
				update_time,
				intro,
				play_infos,
			})
		}

		pub async fn search(&self, name: String) -> Result<Vec<LzizyVideoBase>, String> {
			let search_url = format!(
				"https://search.lziapi.com/json-api/?dname=liangzi&key={}&count=50",
				name
			);
			let res = reqwest::Client::new()
				.get(&search_url)
				.send()
				.await
				.map_err(|e| e.to_string())?;

			if !res.status().is_success() {
				return Err(format!("[无法访问]：{}", search_url));
			}

			let json_data = res.text().await.map_err(|e| e.to_string())?;
			let json_data = serde_json::from_str::<Value>(&json_data).map_err(|e| e.to_string())?;

			let mut video_datas: Vec<LzizyVideoBase> = vec![];

			let posts = json_data["posts"].as_array().unwrap();

			for obj in posts.iter() {
				let type_name = obj["type_name"].as_str().unwrap();
				if !type_name.contains("电影解说") && !type_name.contains("预告片") {
					let id = obj["vod_id"].as_u64().unwrap() as u32;
					let name = obj["vod_name"].as_str().unwrap();
					let cover_url = obj["vod_pic"].as_str().unwrap();
					let video_base: LzizyVideoBase =
						LzizyVideoBase::new(id, String::from(name), String::from(cover_url));

					video_datas.push(video_base);
				}
			}
			println!("{:#?}", video_datas);
			Ok(video_datas)
		}
	}

	/******************** 下列函数实现了前端对结构体关联函数的调用 ********************/

	use std::sync::Arc;
	use tokio::sync::Mutex;

	/** 返回指定频道的视频数据
	 * channel_index：频道索引0-3
	 */
	#[tauri::command]
	pub async fn get_channel_video_data(state: tauri::State<'_, Arc<Mutex<Lzizy>>>, channel_index: u8,) -> Result<Vec<LzizyVideo>, String> {
		let mut lzizy_api = state.lock().await;
		lzizy_api.init().await;

		let mut request_time: Duration = Duration::ZERO;
		let mut processing_data_elapsed: Duration = Duration::ZERO;

		let start_time = std::time::Instant::now();
		let channel_page = lzizy_api.get_channel_page(channel_index).await?;
		request_time += start_time.elapsed();

		let start_time = std::time::Instant::now();
		let channel_page_urls = lzizy_api.get_target_page_url(channel_page);
		processing_data_elapsed += start_time.elapsed();

		let start_time = std::time::Instant::now();
		let target_page = lzizy_api.get_target_page(channel_page_urls).await;
		request_time += start_time.elapsed();

		println!("[请求数据耗时]：{:?}", request_time);

		let start_time = std::time::Instant::now();
		let mut video_list: Vec<LzizyVideo> = vec![];
		for html in target_page {
			video_list.push(lzizy_api.get_video_data(html).await.unwrap());
		}
		processing_data_elapsed += start_time.elapsed();

		Ok(video_list)
	}

	///  实现了对['api::lzizyapi::Lzizy::search']关联方法的调用
	///* name: 视频名称
	#[tauri::command]
	pub async fn search(
		state: tauri::State<'_, Arc<Mutex<Lzizy>>>,
		name: String,
	) -> Result<Vec<LzizyVideoBase>, String> {
		let mut api_obj = state.lock().await;
		api_obj.init().await;

		let video_list = api_obj.search(name).await?;
		Ok(video_list)
	}

	#[tauri::command]
	pub async fn get_target_video_data(
		state: tauri::State<'_, Arc<Mutex<Lzizy>>>,
		vid: u32,
	) -> Result<LzizyVideo, String> {
		let mut api_obj = state.lock().await;
		api_obj.init().await;
		let urls = vec![format!(
			"{0}{1}{2}.html",
			api_obj.current_route, "/index.php/vod/detail/id/", vid
		)];
		println!("[目标视频地址]：{:?}", urls);
		let target_page = api_obj.get_target_page(urls).await;
		let video = api_obj.get_video_data(target_page[0].clone()).await?;
		println!("{:?}", video);
		Ok(video)
	}
}
